#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Ford UK NGc2 爬虫模型数据抓取模块
专门处理基础车型信息的抓取，包括轮播导航和车型选择
"""

import time
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException, StaleElementReferenceException
from .car_series import CarSeries
from .car_object import CarObject
from .car_extras import CarExtras


class ModelScraper:
    """模型数据抓取器"""
    
    def __init__(self, driver, wait, page_utilities):
        """
        初始化模型抓取器
        
        Args:
            driver: WebDriver实例
            wait: WebDriverWait实例
            page_utilities: 页面工具类实例
        """
        self.driver = driver
        self.wait = wait
        self.page_utilities = page_utilities
    
    def scrape_model_data(self, config):
        """
        抓取车型数据的主方法
        
        Args:
            config: 配置信息
            
        Returns:
            CarSeries: 车系对象
        """
        print("📋 开始抓取车型数据...")
        
        try:
            # 解析URL参数
            url = config['sub_model']['url']
            catalog_id, series_code, default_paint = self.page_utilities.parse_url_parameters(url)
            
            # 提取车系名称（从URL中推断）
            model_name = self._extract_model_name_from_url(url)
            
            # 创建车系对象
            car_series = CarSeries(
                car_series_name=model_name,
                catalog_id=catalog_id,
                series_code=series_code,
                default_paint=default_paint
            )
            
            print(f"车系信息: {model_name}, 目录ID: {catalog_id}, 车系代码: {series_code}, 默认颜色: {default_paint}")
            
            sub_models = []
            processed_models = set()  # 防止重复
            
            # 循环获取所有子车型 - 期望找到7个
            max_attempts = 20  # 增加最大尝试次数
            attempt = 0
            no_new_models_count = 0  # 连续没有新车型的次数
            target_models = 7  # 期望的车型数量
            seen_ranges = set()  # 记录已经处理过的分页范围
            
            print(f"开始抓取，期望找到 {target_models} 个车型...")
            
            while attempt < max_attempts and no_new_models_count < 5:
                print(f"第 {attempt + 1} 次尝试获取车型数据...")
                
                # 检查分页指示器
                pagination_info = self.get_pagination_info()
                current_range = None
                if pagination_info:
                    print(f"分页信息: {pagination_info}")
                    current_range = pagination_info.get('current_range', '')
                    
                    # 如果已经处理过这个范围，跳过
                    if current_range in seen_ranges:
                        print(f"范围 {current_range} 已处理过，尝试滚动到下一页...")
                        if not self.scroll_carousel():
                            break
                        attempt += 1
                        continue
                    else:
                        seen_ranges.add(current_range)
                
                # 获取当前页面的车型数据
                current_models = self.get_visible_sub_models()
                initial_count = len(sub_models)
                
                # 处理当前页面的车型
                for model in current_models:
                    model_unique_key = f"{model.get('model_name', '')}_{model.get('price', '')}"
                    if model_unique_key not in processed_models:
                        sub_models.append(model)
                        processed_models.add(model_unique_key)
                        print(f"  ✓ 新增车型: {model.get('model_name', 'Unknown')} - {model.get('price', 'N/A')}")
                
                new_count = len(sub_models)
                found_new_models = new_count > initial_count
                
                print(f"  📊 当前总计: {new_count} 个车型")
                
                if found_new_models:
                    no_new_models_count = 0
                else:
                    no_new_models_count += 1
                    print(f"  ⚠️  连续 {no_new_models_count} 次未发现新车型")
                
                # 如果达到期望数量，提前结束
                if len(sub_models) >= target_models:
                    print(f"✅ 已达到目标数量 ({target_models} 个车型)，结束抓取")
                    break
                
                # 尝试滚动到下一页
                if not self.scroll_carousel():
                    print("无法继续滚动，可能已到最后一页")
                    break
                
                # 等待页面更新
                time.sleep(2)
                attempt += 1
            
            print(f"🎯 抓取完成！总共获得 {len(sub_models)} 个车型数据")
            
            # 创建实体类对象
            self._create_car_objects(car_series, sub_models, model_name)
            
            return car_series
            
        except Exception as e:
            print(f"❌ 抓取车型数据时出错: {e}")
            # 返回空的车系对象作为备用
            return CarSeries("Unknown Series")
    
    def _extract_model_name_from_url(self, url):
        """从URL中提取车系名称"""
        try:
            # 从URL路径中提取车系名称
            if '/cars/' in url:
                path_parts = url.split('/cars/')[-1].split('/')
                model_name = path_parts[0].replace('-', ' ').title()
                return model_name
            elif '/shop/build-and-price/' in url:
                path_parts = url.split('/shop/build-and-price/')[-1].split('/')
                model_name = path_parts[0].replace('-', ' ').title()
                return model_name
            else:
                return "Unknown Series"
        except Exception:
            return "Unknown Series"
    
    def get_pagination_info(self):
        """
        获取分页信息
        
        Returns:
            dict or None: 分页信息
        """
        try:
            # 查找分页指示器
            pagination_selectors = [
                'span[class*="Pagination"]',
                'div[class*="pagination"]',
                '[class*="page-indicator"]',
                '[aria-label*="page"]'
            ]
            
            for selector in pagination_selectors:
                try:
                    elements = self.driver.find_elements(By.CSS_SELECTOR, selector)
                    for element in elements:
                        if element.is_displayed():
                            text = element.text.strip()
                            if text and ('of' in text or '/' in text):
                                return self.parse_pagination_info(text)
                except Exception:
                    continue
            
            return None
            
        except Exception as e:
            print(f"获取分页信息时出错: {e}")
            return None
    
    def parse_pagination_info(self, pagination_text):
        """
        解析分页文本信息
        
        Args:
            pagination_text (str): 分页文本 (如: "1-4 of 6")
            
        Returns:
            dict: 解析后的分页信息
        """
        try:
            # 处理 "1-4 of 6" 格式
            if ' of ' in pagination_text:
                parts = pagination_text.split(' of ')
                total = int(parts[1].strip())
                range_part = parts[0].strip()
                
                if '-' in range_part:
                    start, end = map(int, range_part.split('-'))
                else:
                    start = end = int(range_part)
                
                return {
                    'current_range': f"{start}-{end}",
                    'start': start,
                    'end': end,
                    'total': total
                }
            
            return None
            
        except Exception as e:
            print(f"解析分页信息失败: {e}")
            return None
    
    def get_visible_sub_models(self):
        """
        获取当前可见的子车型数据 - 修复版本避免stale element错误
        
        Returns:
            list: 车型数据列表
        """
        models = []
        
        try:
            # 查找车型元素的多种选择器
            selectors = [
                'div[data-cy][class*="ProductTile"]',
                'div[data-cy]',
                '[class*="ProductTile"]'
            ]
            
            model_elements = []
            for selector in selectors:
                elements = self.driver.find_elements(By.CSS_SELECTOR, selector)
                if elements:
                    model_elements = elements
                    print(f"使用选择器 '{selector}' 找到 {len(elements)} 个车型元素")
                    break
            
            if not model_elements:
                print("警告：未找到任何车型元素")
                return models
            
            # 获取所有元素的基本信息（避免存储元素对象）
            model_info_list = []
            for i, element in enumerate(model_elements):
                try:
                    data_cy = element.get_attribute('data-cy')
                    is_displayed = element.is_displayed()
                    model_info_list.append({
                        'index': i,
                        'data_cy': data_cy,
                        'is_displayed': is_displayed
                    })
                except Exception as e:
                    print(f"获取第{i+1}个元素信息失败: {e}")
                    continue
            
            data_cy_values = [info['data_cy'] for info in model_info_list if info['data_cy']]
            print(f"发现的data-cy值: {data_cy_values}")
            
            # 逐个处理车型（每次重新获取元素避免stale）
            for info in model_info_list:
                if not info['is_displayed']:
                    continue
                    
                try:
                    print(f"处理元素 {info['index']+1}: data-cy='{info['data_cy']}'")
                    
                    # 重新获取新鲜的元素
                    fresh_elements = self.driver.find_elements(By.CSS_SELECTOR, 'div[data-cy][class*="ProductTile"]')
                    if info['index'] >= len(fresh_elements):
                        print(f"元素索引超出范围，跳过")
                        continue
                    
                    fresh_element = fresh_elements[info['index']]
                    
                    # 验证这是正确的元素
                    current_data_cy = fresh_element.get_attribute('data-cy')
                    if current_data_cy != info['data_cy']:
                        print(f"⚠️  元素不匹配: 期望 {info['data_cy']}, 实际 {current_data_cy}")
                        continue
                    
                    model_data = self.extract_model_data_safe(info['index'], info['data_cy'])
                    if model_data:
                        models.append(model_data)
                        print(f"成功提取: {model_data['model_name']} - {model_data['price']}")
                    else:
                        print(f"元素 {info['index']+1} 数据提取失败")
                            
                except Exception as e:
                    print(f"解析第 {info['index']+1} 个车型元素时出错: {e}")
                    continue
        
        except Exception as e:
            print(f"获取车型元素时出错: {e}")
        
        print(f"本轮共提取到 {len(models)} 个有效车型")
        return models
    
    def extract_model_data_safe(self, model_index, data_cy):
        """安全地从单个车型元素中提取数据，避免stale element错误"""
        try:
            # 重新获取新鲜的元素
            elements = self.driver.find_elements(By.CSS_SELECTOR, 'div[data-cy][class*="ProductTile"]')
            if model_index >= len(elements):
                print(f"元素索引{model_index}超出范围")
                return None
            
            element = elements[model_index]
            
            # 验证这是正确的元素
            current_data_cy = element.get_attribute('data-cy')
            if current_data_cy != data_cy:
                print(f"元素不匹配: 期望{data_cy}, 实际{current_data_cy}")
                return None
            
            # 提取车型名称
            name_elements = element.find_elements(
                By.CSS_SELECTOR, 'strong[class*="ProductTileAttributeValue"]'
            )
            
            model_name = None
            price = None
            
            for name_elem in name_elements:
                text = name_elem.text.strip()
                
                # 识别价格（以£开头）
                if text.startswith('£'):
                    price = text
                # 识别车型名称（不是价格的文本）
                elif text and not text.startswith('£') and not model_name:
                    model_name = text
            
            # 如果没有找到名称，使用data-cy
            if not model_name:
                model_name = data_cy
            
            if model_name and price:
                # 点击View Specifications按钮获取Key Features
                key_features = self.get_key_features_robust(model_index, data_cy, model_name)
                
                return {
                    "model_name": model_name,
                    "price": price,
                    "Key Features": key_features
                }
            
            return None
            
        except Exception as e:
            print(f"安全提取车型数据时出错: {e}")
            return None

    def get_key_features_robust(self, model_index, data_cy, model_name):
        """使用强健的方法获取Key Features"""
        try:
            print(f"    🔍 获取 {model_name} 的Key Features...")
            
            # 重新获取元素
            elements = self.driver.find_elements(By.CSS_SELECTOR, 'div[data-cy][class*="ProductTile"]')
            if model_index >= len(elements):
                print(f"    ❌ 重新获取元素失败，索引超出范围")
                return []
            
            element = elements[model_index]
            
            # 滚动到元素
            self.driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", element)
            time.sleep(1)
            
            # 长时间悬停，确保按钮完全显示
            from selenium.webdriver.common.action_chains import ActionChains
            actions = ActionChains(self.driver)
            actions.move_to_element(element).perform()
            time.sleep(3)  # 延长悬停时间
            
            # 查找View Specifications按钮
            spec_button = None
            selectors = [
                'button[data-cy="product-tile-overlay"]',
                'button[class*="ButtonAsLink"]',
                'a[data-cy="product-tile-overlay"]',  # 可能是链接而不是按钮
            ]
            
            for selector in selectors:
                try:
                    buttons = element.find_elements(By.CSS_SELECTOR, selector)
                    for btn in buttons:
                        # 检查按钮文本或属性
                        data_cy_attr = btn.get_attribute('data-cy')
                        if data_cy_attr == 'product-tile-overlay':
                            spec_button = btn
                            print(f"    ✓ 找到按钮 (选择器: {selector})")
                            break
                    if spec_button:
                        break
                except Exception as e:
                    print(f"    ❌ 选择器 {selector} 失败: {e}")
                    continue
            
            if not spec_button:
                print(f"    ❌ 未找到View Specifications按钮")
                return []
            
            # 记录原始URL
            original_url = self.driver.current_url
            
            # 尝试点击按钮
            if self.robust_click_button(spec_button, f"{model_name} View Specs"):
                print(f"    🎯 按钮点击成功，等待页面响应...")
                time.sleep(4)  # 给更多时间让页面响应
                
                # 检查是否有页面变化
                current_url = self.driver.current_url
                if current_url != original_url:
                    print(f"    🌐 页面已导航到新页面")
                else:
                    print(f"    📋 可能打开了模态框，保持在原页面")
                
                # 尝试提取Key Features
                key_features = self.extract_key_features_comprehensive()
                
                # 导航回原页面（如果需要）
                if current_url != original_url:
                    print(f"    🔄 导航回原页面...")
                    self.driver.get(original_url)
                    from selenium.webdriver.support.ui import WebDriverWait
                    from selenium.webdriver.support import expected_conditions as EC
                    WebDriverWait(self.driver, 10).until(
                        EC.presence_of_element_located((By.CSS_SELECTOR, 'div[data-cy][class*="ProductTile"]'))
                    )
                    time.sleep(2)
                
                return key_features
            else:
                print(f"    ❌ 所有点击方法都失败")
                return []
        
        except Exception as e:
            print(f"    ❌ 获取Key Features时出错: {e}")
            return []

    def robust_click_button(self, button, method_name="未知"):
        """使用多种方法尝试点击按钮"""
        try:
            print(f"    🖱️  尝试点击按钮 ({method_name})...")
            
            # 方法1：滚动到按钮并等待
            self.driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", button)
            time.sleep(0.5)
            
            # 方法2：JavaScript点击 (最可靠)
            try:
                self.driver.execute_script("arguments[0].click();", button)
                print(f"    ✅ JavaScript点击成功")
                return True
            except Exception as e:
                print(f"    ❌ JavaScript点击失败: {e}")
            
            # 方法3：ActionChains点击
            try:
                from selenium.webdriver.common.action_chains import ActionChains
                actions = ActionChains(self.driver)
                actions.move_to_element(button).click().perform()
                print(f"    ✅ ActionChains点击成功")
                return True
            except Exception as e:
                print(f"    ❌ ActionChains点击失败: {e}")
            
            # 方法4：直接Selenium点击
            try:
                button.click()
                print(f"    ✅ 直接点击成功")
                return True
            except Exception as e:
                print(f"    ❌ 直接点击失败: {e}")
            
            # 方法5：强制可见性后点击
            try:
                self.driver.execute_script("arguments[0].style.visibility = 'visible';", button)
                self.driver.execute_script("arguments[0].style.display = 'block';", button)
                time.sleep(0.5)
                self.driver.execute_script("arguments[0].click();", button)
                print(f"    ✅ 强制可见性点击成功")
                return True
            except Exception as e:
                print(f"    ❌ 强制可见性点击失败: {e}")
            
            return False
            
        except Exception as e:
            print(f"    ❌ 所有点击方法都失败: {e}")
            return False

    def extract_key_features_comprehensive(self):
        """全面搜索Key Features - 修复版本"""
        try:
            time.sleep(2)
            
            key_features = []
            
            # 策略1：专门查找Key Features区域的列表项
            primary_selectors = [
                # 最精确的选择器 - 基于HTML分析结果
                '.ProductTileSection__ProductTileListWrapper-sc-5noent-26.jlFCIP li',
                'div[class*="ProductTileListWrapperOuter"] ul li',
                'h3:contains("Key Features") + ul li',
                # 备用选择器
                'div[class*="ProductTileListWrapper"] li',
                'ul[class*="ProductTileListWrapper"] li',
                'div[class*="ProductTileSection"] ul li'
            ]
            
            for selector in primary_selectors:
                try:
                    # 对于contains选择器需要特殊处理
                    if ':contains(' in selector:
                        # 使用XPath来处理contains
                        xpath = "//h3[contains(text(), 'Key Features')]/following-sibling::ul//li"
                        elements = self.driver.find_elements(By.XPATH, xpath)
                    else:
                        elements = self.driver.find_elements(By.CSS_SELECTOR, selector)
                    
                    if elements:
                        print(f"    ✓ 主要选择器 {selector} 找到 {len(elements)} 个特性")
                        for elem in elements:
                            text = elem.text.strip()
                            # 过滤导航菜单项和无效文本
                            if (text and len(text) > 5 and 
                                text not in ['Model', 'Drive', 'Bodystyle', 'Colour', 'Interior', 'Extras', 'Summary'] and
                                text not in key_features and
                                not any(skip in text.lower() for skip in ['price', 'from', '£', 'total', 'monthly'])):
                                key_features.append(text)
                        
                        if key_features:
                            print(f"    ✓ 成功提取到 {len(key_features)} 个Key Features")
                            return key_features[:15]  # 返回前15个，确保完整性
                except Exception as e:
                    print(f"    ❌ 选择器 {selector} 失败: {e}")
                    continue
            
            # 策略2：如果主要选择器失败，尝试通用的li选择器但加强过滤
            print("    🔄 尝试通用li选择器并加强过滤...")
            try:
                elements = self.driver.find_elements(By.CSS_SELECTOR, 'ul li')
                temp_features = []
                for elem in elements:
                    text = elem.text.strip()
                    # 更严格的过滤条件
                    if (text and 10 < len(text) < 120 and  # 长度限制
                        text not in ['Model', 'Drive', 'Bodystyle', 'Colour', 'Interior', 'Extras', 'Summary'] and  # 排除导航
                        not any(skip in text.lower() for skip in ['price', 'from', '£', 'total', 'monthly', 'view', 'select']) and  # 排除价格和按钮
                        any(feature_keyword in text.lower() for feature_keyword in ['alloy', 'wheel', 'touchscreen', 'keyless', 'led', 'heated', 'driver', 'audio', 'digital', 'premium', 'power', 'assistance']) and  # 包含特征关键词
                        text not in temp_features):
                        temp_features.append(text)
                
                if temp_features:
                    print(f"    ✓ 通用选择器找到 {len(temp_features)} 个特性")
                    return temp_features[:15]
            except Exception as e:
                print(f"    ❌ 通用选择器失败: {e}")
            
            print(f"    ⚠️  未找到任何Key Features")
            return []
            
        except Exception as e:
            print(f"    ❌ 提取Key Features失败: {e}")
            return []

    def scroll_carousel(self):
        """滚动轮播组件"""
        try:
            # 方法1：使用正确的下一页按钮选择器
            next_button_selectors = [
                'button[aria-label="Move to next element"][action="next"]',
                'button.PaginationArrowBtn-sc-1o074yf-0.fXZRaw[action="next"]',
                'button[action="next"]',
                'button[aria-label*="Move to next"]',
                '.PaginationArrowBtn-sc-1o074yf-0[action="next"]'
            ]
            
            for selector in next_button_selectors:
                try:
                    next_buttons = self.driver.find_elements(By.CSS_SELECTOR, selector)
                    
                    for button in next_buttons:
                        if button.is_displayed():
                            # 检查按钮是否可用（不是disabled状态）
                            aria_disabled = button.get_attribute('aria-disabled')
                            if aria_disabled == 'true':
                                print("下一页按钮已禁用，可能已到达最后一页")
                                return False
                            
                            print(f"找到下一页按钮，使用选择器: {selector}")
                            
                            # 滚动到按钮可见
                            self.driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", button)
                            time.sleep(0.5)
                            
                            # 点击按钮
                            button.click()
                            print("✓ 成功点击下一页按钮")
                            
                            # 等待页面更新
                            time.sleep(2)
                            return True
                            
                except Exception as e:
                    print(f"使用选择器 {selector} 失败: {e}")
                    continue
            
            print("❌ 未找到可用的下一页按钮")
            return False
            
        except Exception as e:
            print(f"滚动轮播时出错: {e}")
            return False

    def _create_car_objects(self, car_series, sub_models, model_name):
        """创建CarObject实例"""
        # 创建实体类对象
        for i, model in enumerate(sub_models):
            model_name_str = model.get('model_name', 'Unknown')
            price = model.get('price', '')
            key_features = model.get('Key Features', [])
            
            print(f"创建车款实体类: {model_name_str}")
            
            # 创建车款实体类
            car_object = CarObject(
                series_name=model_name,  # 车系名
                model_name=model_name_str,  # 车款名
                price=price,
                drive=""  # 暂时为空，后续可以扩展
            )
            
            # 添加Key Features
            for feature in key_features:
                if feature and feature.strip():  # 只添加非空的特性
                    car_object.add_key_feature(feature)
            
            # 添加一些默认的颜色（作为示例）
            car_object.add_color("red")
            car_object.add_color("blue")
            car_object.add_color("yellow")
            
            # 添加示例选装件
            extra1 = CarExtras("Blind Spot Information System with Blind Spot Assist & Trailer Coverage", "$1234")
            extra2 = CarExtras("Driver Assist Pack", "$575")
            car_object.add_extra(extra1)
            car_object.add_extra(extra2)
            
            # 添加到车系
            car_series.add_car_object(car_object)
        
        print(f"✅ 成功创建 {car_series.get_car_objects_count()} 个CarObject实例")